#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <vector>
using namespace std;

template <typename T>
class Singleton {
public:
    static T& getInstance() {
        if (!instance) {
            lock_guard<mutex> lock(mutex_);
            if (!instance) {
                instance = new T();
            }
        }
        return *instance;
    }

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

protected:
    Singleton() = default;
    ~Singleton() = default;

private:
    static T* instance;
    static mutex mutex_;
};

template <typename T>
T* Singleton<T>::instance = nullptr;

template <typename T>
mutex Singleton<T>::mutex_;

class Point : public Singleton<Point> {
public:
    void print(int x, int y) {
        cout << x << " " << y << endl;
    }
};

void test1() {
    Point& p = Point::getInstance();
    p.print(1, 2);
}

constexpr int NUM_THREADS = 5;
std::atomic<int> thread_count(0);

void thread_function() {
    // 每个线程都打印实例的地址，并调用 print 方法打印坐标
    Point& p = Point::getInstance();
    std::cout << "Thread ID: " << std::this_thread::get_id() << ", Singleton instance address: " << &p << std::endl;
    p.print(1, 2);

    // 原子计数器增加，用于标记所有线程都已完成
    thread_count.fetch_add(1, std::memory_order_relaxed);
}

void test2() {
    std::vector<std::thread> threads;

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; ++i) {
        threads.emplace_back(thread_function);
    }

    // 等待所有线程完成
    while (thread_count.load(std::memory_order_relaxed) < NUM_THREADS) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    // 所有线程完成后，主线程继续执行
    std::cout << "All threads completed." << std::endl;

    // 等待所有线程退出
    for (auto& thread : threads) {
        thread.join();
    }
}

int main(int argc, const char* argv[]) {
    if (argc != 2) {
        cerr << "Usage: " << argv[0] << " <TestCase_Number>" << endl;
        return 1;
    }

    string testcase = argv[1];

    if (testcase == "1") {
        test1();
    } else if (testcase == "2") {
        test2();
    } else {
        cerr << "Invalid TestCase_Number: " << testcase << endl;
        return 1;
    }

    return 0;
}